package main.java.LeetCode.ClassicalAlgorithm.Exp.Impl;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Stack;

@SuppressWarnings("ALL")
public class Exp {

    private static final HashMap<Character,Integer> order;
    static {
        order = new HashMap<>();
        order.put('*',2);
        order.put('/',2);
        order.put('+',1);
        order.put('-',1);
    }


    /**
     * 计算中缀表达式的值
     * @param nifix
     * @return
     */
    public String expCalculateByNifix(String nifix){
        return doCalculate(NifixExpToPrefixExp(nifix));
    }

    /**
     * 中缀转前缀
     * @param nifix
     * @return
     */
    public LinkedList<String> NifixExpToPrefixExp(String nifix){
        LinkedList<String> num = new LinkedList<>();
        Stack<Character> operators = new Stack<>();

        for(int i = nifix.length()-1;i>=0;i--){
            char nowObj = nifix.charAt(i);

            if(isBracket(nowObj,operators,num))
                continue;


            /**
             * 判断是不是数字
             */
            if(Character.isDigit(nowObj)){
                StringBuilder sb = new StringBuilder();
                int index = i;

                for(int left = i;left>=0;left--){
                    if(Character.isDigit(nifix.charAt(left)))
                    {
                        sb.append(nifix.charAt(left));
                        index--;
                    }
                    else
                        break;
                }
                i = index+1;
                num.push(sb.reverse().toString());
                continue;
            }

            if(operators.isEmpty()||operators.peek()==')'){
                operators.push(nowObj);
                continue;
            }

            while (order.get(nowObj)<order.get(operators.peek())){
                num.push(operators.pop().toString());
            }
            operators.push(nowObj);
        }

        while (!operators.isEmpty()){
            num.push(operators.pop().toString());
        }

        System.out.println("反向的前缀表达式："+num);

        return num;
    }

    /**
     * 判断是否是括号
     * @param nowObj
     * @param operators
     * @param num
     * @return
     */
    private boolean isBracket(Character nowObj,Stack<Character> operators,LinkedList<String> num){
        if(nowObj==')'){
            operators.push(nowObj);
            return true;
        }

        if(nowObj=='('){
            while (operators.peek()!=')')
                num.push(operators.pop().toString());

            operators.pop();
            return true;
        }
        return false;
    }

    /**
     * 根据前缀表达式计算结果
     * @param nums
     * @return
     */
    private String doCalculate(LinkedList<String> nums){
        Stack<String> res = new Stack<>();
        while (!nums.isEmpty()){
            String now = nums.pollLast();
            if(isOperator(now)){
                String s = DoubleCount(res.pop(), res.pop(), now);
                res.push(s);
            }
            else
                res.push(now);
        }
        return res.pop();
    }

    /**
     * 判断是否是操作符
     * @param now
     * @return
     */
    private boolean isOperator(String now){
        if(now.equals("+")||now.equals("*")||now.equals("/")||now.equals("-"))
            return true;
        return false;
    }

    /**
     * 计算操作数的值
     * @param num1
     * @param num2
     * @param operator
     * @return
     */
    private String DoubleCount(String num1,String num2,String operator){
        Double d1 = Double.valueOf(num1);
        Double d2 = Double.valueOf(num2);
        Double res = 0.0;

        switch (operator){
            case "*":
                res = d1*d2;
                break;
            case "/":
                res = d1/d2;
                break;
            case "-":
                res = d1-d2;
                break;
            case "+":
                res = d1+d2;
                break;
        }
        return String.valueOf(res);
    }


}
